package net.csdn.business.webhook.service.impl;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.domain.request.webhook.NewWebhookLogDTO;
import net.csdn.business.common.domain.request.webhook.WebhookNotifyDTO;
import net.csdn.business.webhook.config.properties.OkHttpsProperties;
import net.csdn.business.webhook.service.INotifyService;
import net.csdn.business.webhook.service.IWebhookLogService;
import net.csdn.business.webhook.utils.SignatureUtil;
import okhttp3.*;
import okio.Buffer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.PostConstruct;
import javax.net.ssl.*;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName NotifyServiceImpl
 * @Description 通知服务实现类接口
 * @Author zhangyl
 * @Date 2023/4/28 14:20
 */
@Slf4j
@Service
public class NotifyServiceImpl implements INotifyService {

    @Autowired
    private OkHttpsProperties okHttpsProperties;

    @Autowired
    private IWebhookLogService webhookLogService;

    private OkHttpClient.Builder notifyHttpClientBuilder;



    @PostConstruct
    private void init(){
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        //配置连接超时时间（默认10秒）
        builder.connectTimeout(okHttpsProperties.getConnectTimeout(), TimeUnit.SECONDS);
        //配置读取数据超时时间
        builder.readTimeout(okHttpsProperties.getReadTimeout(), TimeUnit.SECONDS);
        builder.writeTimeout(okHttpsProperties.getWriteTimeout(), TimeUnit.SECONDS);
        //配置okHttp3请求https信任忽略所有证书
        try{
            final TrustManager[] trustAllCerts =new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }
                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }
                        @Override
                        public java.security.cert.X509Certificate[]getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };
            final SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            //builder.sslSocketFactory(sslSocketFactory ）方法已过时，使用下面方法替代
            builder.sslSocketFactory(sslSocketFactory,(X509TrustManager)trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    //支持所有类型https请求
                    return true;
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }
        this.notifyHttpClientBuilder=builder;
    }


  /*  @Override
    @Async("notifyTaskExecutor")
    public void sendPostWithForm(WebhookNotifyDTO notifyParams) throws IOException {
        String url=notifyParams.getUrl();
        String secret=notifyParams.getSecret();
        Map<String, String> headerParams=notifyParams.getHeaderParams();
        String payload=notifyParams.getPayload();
        NewWebhookLogDTO notifyLog=new NewWebhookLogDTO();
        notifyLog.setDeliveryId(notifyParams.getDeliveryId());
        notifyLog.setReqUrl(url);
        notifyLog.setReqData(payload);
        notifyLog.setTriggerEvent(notifyParams.getEventType());
        notifyLog.setWebHookId(notifyParams.getWebhookId());
        //Map params =(Map) JSONObject.parseObject(payload,Map.class);
        FormBody.Builder formBuilder = new FormBody.Builder();
        formBuilder.add("payload", payload);
        *//*if(params!=null&&params.size()>0){
            Set<String> keySet = params.keySet();
            for (String key : keySet) {
                Object value=params.get(key);
                if(value==null){
                    formBuilder.add(key, "");
                }else{
                    formBuilder.add(key,String.valueOf(value));
                }
            }
        }*//*
        RequestBody requestBody=formBuilder.build();
        //判断用户在webhook是否配置了secret,如果配置了，则生成HmacSha1和HmacSha256签名
        if(StringUtils.isNotBlank(secret)){
            //获取form拼接好的请求参数生成签名
            Buffer buffer = new Buffer();
            requestBody.writeTo(buffer);
            String bodyString =buffer.readUtf8();
            //进行urldecode解码
            //bodyString = URLDecoder.decode(bodyString, StandardCharsets.UTF_8.toString());
            log.info("post requestBody ={}", bodyString);
            //生成签名
            String sha1= SignatureUtil.genSha1Sign(bodyString,secret);
            headerParams.put("X-Hub-Signature",sha1);
            log.info("requestBody-sha1--sign ={}", sha1);
            String sha256= SignatureUtil.genSha256Sign(bodyString,secret);
            headerParams.put("X-Hub-Signature-256",sha256);
            log.info("requestBody-sha256--sign ={}", sha256);
        }
        OkHttpClient client = notifyHttpClientBuilder.build();
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        log.info("post url={}", url);
        if (headerParams != null && headerParams.size() > 0) {
            Headers headers=Headers.of(headerParams);
            builder.headers(headers);
            log.debug("post headers={}", headers);
        }

        builder.post(requestBody);
        StopWatch watch = new StopWatch();
        watch.start();
        try {
            Response response = client.newCall(builder.build()).execute();
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.info("url-----{},protocol-----{},code-----{},execDuration-----{}s,message-----{}", url, response.protocol(), response.code(),execDuration, response.message());
            String string = response.body().string();
            //log.debug("response: {}", string);
            notifyLog.setResBody(string);
            Integer status=response.code();
            notifyLog.setResStatus(status.toString());
            String message=response.message();
            notifyLog.setInternalErrorMessage(message);
            Headers headers = response.headers();
            JSONObject headerJson=new JSONObject();
            if(headers!=null) {
                Set<String> names = headers.names();
                for (String name : names) {
                    String value = headers.get(name);
                    // 将旧请求的头设置到新请求中
                    headerJson.put(name, value);
                }
            }
            notifyLog.setResHeaders(headerJson.toString());
        } catch (Exception e) {
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.debug("url={},onFailure: {}", url, e.getMessage());
            //log.debug("getStackTrace: {}", e.getStackTrace());
            notifyLog.setInternalErrorMessage(e.getMessage());
        }finally {
            headerParams.put("Request URL",url);
            headerParams.put("Request method","POST");
            notifyLog.setReqHeaders(JSON.toJSONString(headerParams));
            //记录通知日志
            webhookLogService.insertWebhookLog(notifyLog);
        }
    }

    @Override
    @Async("notifyTaskExecutor")
    public void sendPostWithJson(WebhookNotifyDTO notifyParams) throws IOException {
        String url=notifyParams.getUrl();
        String secret=notifyParams.getSecret();
        Map<String, String> headerParams=notifyParams.getHeaderParams();
        String payload=notifyParams.getPayload();
        NewWebhookLogDTO notifyLog=new NewWebhookLogDTO();
        notifyLog.setDeliveryId(notifyParams.getDeliveryId());
        notifyLog.setReqUrl(url);
        notifyLog.setReqData(payload);
        notifyLog.setTriggerEvent(notifyParams.getEventType());
        notifyLog.setWebHookId(notifyParams.getWebhookId());
        //判断用户在webhook是否配置了secret,如果配置了，则生成HmacSha1和HmacSha256签名
        if(StringUtils.isNotBlank(secret)){
            //生成签名
            String sha1= SignatureUtil.genSha1Sign(payload,secret);
            headerParams.put("X-Hub-Signature",sha1);
            log.info("requestBody-sha1--sign ={}", sha1);
            String sha256= SignatureUtil.genSha256Sign(payload,secret);
            headerParams.put("X-Hub-Signature-256",sha256);
            log.info("requestBody-sha256--sign ={}", sha256);
        }

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), payload);
        OkHttpClient client = notifyHttpClientBuilder.build();
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        log.info("post url={}", url);
        if (headerParams != null && headerParams.size() > 0) {
            Headers headers=Headers.of(headerParams);
            builder.headers(headers);
            log.debug("post headers={}", headers);
        }
        log.info("post requestBody ={}", requestBody);
        builder.post(requestBody);
        StopWatch watch = new StopWatch();
        watch.start();
        try {
            Response response = client.newCall(builder.build()).execute();
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.info("url={},protocol:{},code:{},execDuration:{},message:{}", url, response.protocol(), response.code(),execDuration, response.message());
            String string = response.body().string();
            log.debug("response: {}", string);
            notifyLog.setResBody(string);
            Integer status=response.code();
            notifyLog.setResStatus(status.toString());
            String message=response.message();
            notifyLog.setInternalErrorMessage(message);
            Headers headers = response.headers();
            JSONObject headerJson=new JSONObject();
            if(headers!=null) {
                Set<String> names = headers.names();
                for (String name : names) {
                    String value = headers.get(name);
                    // 将旧请求的头设置到新请求中
                    headerJson.put(name, value);
                }
            }
            notifyLog.setResHeaders(headerJson.toString());
        } catch (Exception e) {
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.debug("url={},onFailure: {}", url, e.getMessage());
            //log.debug("getStackTrace: {}", e.getStackTrace());
            notifyLog.setInternalErrorMessage(e.getMessage());
        }finally {
            //记录通知日志
            headerParams.put("Request URL",url);
            headerParams.put("Request method","POST");
            notifyLog.setReqHeaders(JSON.toJSONString(headerParams));
            webhookLogService.insertWebhookLog(notifyLog);
        }
    }*/

    @Override
    @Async("notifyTaskExecutor")
    public void sendNotify(WebhookNotifyDTO notifyParams) throws IOException {
        String url=notifyParams.getUrl();
        String secret=notifyParams.getSecret();
        Map<String, String> headerParams=notifyParams.getHeaderParams();
        String payload=notifyParams.getPayload();
        NewWebhookLogDTO notifyLog=new NewWebhookLogDTO();
        notifyLog.setDeliveryId(notifyParams.getDeliveryId());
        notifyLog.setReqUrl(url);
        notifyLog.setReqData(payload);
        notifyLog.setTriggerEvent(notifyParams.getEventType());
        notifyLog.setWebHookId(notifyParams.getWebhookId());
        //判断用户在webhook是否配置了secret,如果配置了，则生成HmacSha1和HmacSha256签名
        if(StringUtils.isNotBlank(secret)){
            //生成签名
            String sha1= SignatureUtil.genSha1Sign(payload,secret);
            headerParams.put("X-Hub-Signature",sha1);
            log.info("requestBody-sha1--sign ={}", sha1);
            String sha256= SignatureUtil.genSha256Sign(payload,secret);
            headerParams.put("X-Hub-Signature-256",sha256);
            log.info("requestBody-sha256--sign ={}", sha256);
        }
        Integer reqBodyType=notifyParams.getReqBodyType();
        OkHttpClient client = notifyHttpClientBuilder.build();
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        if (headerParams != null && headerParams.size() > 0) {
            Headers headers=Headers.of(headerParams);
            builder.headers(headers);
            log.debug("post headers={}", headers);
        }
        RequestBody requestBody =null;
        if(reqBodyType==1){
            requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), payload);
        }else{
            FormBody.Builder formBuilder = new FormBody.Builder();
            formBuilder.add("payload", payload);
            requestBody=formBuilder.build();
        }
        log.info("post url={}", url);
        log.info("post requestBody ={}", requestBody);
        builder.post(requestBody);
        StopWatch watch = new StopWatch();
        watch.start();
        try {
            Response response = client.newCall(builder.build()).execute();
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.info("url={},protocol:{},code:{},execDuration:{},message:{}", url, response.protocol(), response.code(),execDuration, response.message());
            String string = response.body().string();
            log.debug("response: {}", string);
            notifyLog.setResBody(string);
            Integer status=response.code();
            notifyLog.setResStatus(status.toString());
            String message=response.message();
            notifyLog.setInternalErrorMessage(message);
            Headers respheaders = response.headers();
            JSONObject resHeaderJson=new JSONObject();
            if(respheaders!=null) {
                Set<String> names = respheaders.names();
                for (String name : names) {
                    String value = respheaders.get(name);
                    // 将旧请求的头设置到新请求中
                    resHeaderJson.put(name, value);
                }
            }
            notifyLog.setResHeaders(resHeaderJson.toString());
        } catch (Exception e) {
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.debug("url={},onFailure: {}", url, e.getMessage());
            //log.debug("getStackTrace: {}", e.getStackTrace());
            notifyLog.setInternalErrorMessage(e.getMessage());
        }finally {
            //记录通知日志
            headerParams.put("Request URL",url);
            headerParams.put("Request method","POST");
            notifyLog.setReqHeaders(JSON.toJSONString(headerParams));
            notifyLog.setIsRedelivery(notifyParams.getIsRedelivery());
            webhookLogService.insertWebhookLog(notifyLog);
        }
    }


    @Override
    @Async("notifyTaskExecutor")
    public void sendRedelivery(WebhookNotifyDTO notifyParams) throws IOException {
        String url=notifyParams.getUrl();
        String secret=notifyParams.getSecret();
        Map<String, String> headerParams=notifyParams.getHeaderParams();
        String payload=notifyParams.getPayload();
        NewWebhookLogDTO notifyLog=new NewWebhookLogDTO();
        notifyLog.setDeliveryId(notifyParams.getDeliveryId());
        notifyLog.setReqUrl(url);
        notifyLog.setReqData(payload);
        notifyLog.setTriggerEvent(notifyParams.getEventType());
        notifyLog.setWebHookId(notifyParams.getWebhookId());
        //判断用户在webhook是否配置了secret,如果配置了，则生成HmacSha1和HmacSha256签名
        if(StringUtils.isNotBlank(secret)){
            //生成签名
            String sha1= SignatureUtil.genSha1Sign(payload,secret);
            headerParams.put("X-Hub-Signature",sha1);
            log.info("requestBody-sha1--sign ={}", sha1);
            String sha256= SignatureUtil.genSha256Sign(payload,secret);
            headerParams.put("X-Hub-Signature-256",sha256);
            log.info("requestBody-sha256--sign ={}", sha256);
        }
        Integer reqBodyType=notifyParams.getReqBodyType();
        OkHttpClient client = notifyHttpClientBuilder.build();
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        if (headerParams != null && headerParams.size() > 0) {
            Headers headers=Headers.of(headerParams);
            builder.headers(headers);
            log.debug("post headers={}", headers);
        }
        RequestBody requestBody =null;
        if(reqBodyType==1){
             requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), payload);
        }else{
            FormBody.Builder formBuilder = new FormBody.Builder();
            formBuilder.add("payload", payload);
            requestBody=formBuilder.build();
        }
        log.info("post url={}", url);
        log.info("post requestBody ={}", requestBody);
        builder.post(requestBody);
        StopWatch watch = new StopWatch();
        watch.start();
        try {
            Response response = client.newCall(builder.build()).execute();
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.info("url={},protocol:{},code:{},execDuration:{},message:{}", url, response.protocol(), response.code(),execDuration, response.message());
            String string = response.body().string();
            log.debug("response: {}", string);
            notifyLog.setResBody(string);
            Integer status=response.code();
            notifyLog.setResStatus(status.toString());
            String message=response.message();
            notifyLog.setInternalErrorMessage(message);
            Headers respheaders = response.headers();
            JSONObject resHeaderJson=new JSONObject();
            if(respheaders!=null) {
                Set<String> names = respheaders.names();
                for (String name : names) {
                    String value = respheaders.get(name);
                    // 将旧请求的头设置到新请求中
                    resHeaderJson.put(name, value);
                }
            }
            notifyLog.setResHeaders(resHeaderJson.toString());
        } catch (Exception e) {
            watch.stop();
            Double execDuration=watch.getTotalTimeSeconds();
            notifyLog.setExecDuration(execDuration);
            log.debug("url={},onFailure: {}", url, e.getMessage());
            //log.debug("getStackTrace: {}", e.getStackTrace());
            notifyLog.setInternalErrorMessage(e.getMessage());
        }finally {
            //记录通知日志
            headerParams.put("Request URL",url);
            headerParams.put("Request method","POST");
            notifyLog.setReqHeaders(JSON.toJSONString(headerParams));
            notifyLog.setIsRedelivery(notifyParams.getIsRedelivery());
            webhookLogService.insertWebhookLog(notifyLog);
        }
    }
}
